/*
	Lirduino - Arduino implementation of the LIRC lircd.conf format
	Copyright (C) 2013  Luke Vibert
	
	Version 0.1 Feb 2013

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
	Utilises sending functions from IRremote: 
		Version 0.11 August, 2009
		Copyright 2009 Ken Shirriff
		For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html

*/

#include "lirduino.h"
#include "IRremoteInt.h"

lirduino::lirduino() {
	NO_HEAD_REP = 0;
	NO_FOOT_REP = 0;
	CONST_LENGTH = 1;
	REPEAT_HEADER = 0;
	REVERSE = 0;
}

void lirduino::sendKey(unsigned long keycode) {
	enableIROut(freq);
	
	int repeatCount = 0;
	while (repeatCount <= min_repeat) {
		unsigned long start = micros();		//log start time for gap calc when using CONST_HEADER flag
		sendHeader();
		sendPreSignal();
		sendKeyData(keycode);
		sendPostSignal();
		sendFooter();
		sendGap(start);
		repeatCount++; 
	}
}

void lirduino::sendHeader() {
	//Send header & lead pulse. If not defined durations = 0 and nothing is done
	mark(header[0]);
	space(header[1]);
	mark(plead);
	space(0);
}

void lirduino::sendPreSignal()	{
	//Send pre_data package
	unsigned long data = pre_data ;
	for (int i = 0; i < pre_data_bits; i++) {
		if (data & TOPBIT) {
			transmit1();
		}
		else {
			transmit0();
		}
	data <<= 1;
	}
	//Send pre pulse and space
	mark(pre[0]);
	space(pre[1]);
}

void lirduino::sendKeyData(unsigned long keycode) {
	unsigned long data = keycode;
	for (int i = 0; i < bits; i++) {
		if (data & TOPBIT) {
			transmit1();
		}
		else {
			transmit0();
		}
	data <<= 1;
	}
}

void lirduino::sendPostSignal()	{
	//Send post pulse and space
	mark(pre[0]);
	space(pre[1]);
	
	//Send post_data package
	unsigned long data = post_data ;
	for (int i = 0; i < post_data_bits; i++) {
		if (data & TOPBIT) {
			transmit1();
		}
		else {
			transmit0();
		}
	data <<= 1;
	}
}

void lirduino::sendFooter() {
	mark(ptrail);
	space(0);
	mark(foot[0]);
	space(foot[1]);
}

void lirduino::sendGap(unsigned long start) {
	if (CONST_LENGTH) {
		unsigned long j = millis() - start;
		space(j);
	}
	else 
		space(gap);
}

void lirduino::transmit1() {
	mark(one[0]);
	space(one[1]);
}

void lirduino::transmit0() {
	mark(zero[0]);
	space(zero[1]);
}

void lirduino::enableIROut(int hz) {
  // Enables IR output.  The khz value controls the modulation frequency in kilohertz.
  // The IR output will be on pin 3 (OC2B).
  // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
  // to make sure it gives reasonable results.  (Watch out for overflow / underflow / rounding.)
  // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
  // controlling the duty cycle.
  // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
  // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
  // A few hours staring at the ATmega documentation and this will all make sense.
  // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
	int khz = hz / 1000;	//convert LIRC hz to khz used by this function
  
  // Disable the Timer2 Interrupt (which is used for receiving IR)
  TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
  
  pinMode(TIMER_PWM_PIN, OUTPUT);
  digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
  
  // COM2A = 00: disconnect OC2A
  // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
  // WGM2 = 101: phase-correct PWM with OCRA as top
  // CS2 = 000: no prescaling
  // The top value for the timer.  The modulation frequency will be SYSCLOCK / 2 / OCR2A.
  TIMER_CONFIG_KHZ(khz);
}

//IR SEND FUNCTIONS
void lirduino::mark(int time) {
  // Sends an IR mark for the specified number of microseconds.
  // The mark output is modulated at the PWM frequency.
  TIMER_ENABLE_PWM; // Enable pin 3 PWM output
  delayMicroseconds(time);
}

/* Leave pin off for time (given in microseconds) */
void lirduino::space(int time) {
  // Sends an IR space for the specified number of microseconds.
  // A space is no output, so the PWM output is disabled.
  TIMER_DISABLE_PWM; // Disable pin 3 PWM output
  delayMicroseconds(time);
}
